<template>
  <div class="three-display three-init">
    <div
      @mousemove="mousemove"
      id="three-canvas"
      class="three-canvas"
      ref="threeCanvas"
    ></div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted, onBeforeUnmount } from "vue";
import Stats from "../../../../node_modules/three/examples/jsm/libs/stats.module";
import * as THREE from "three";
import { OrbitControls } from "../../../../node_modules/three/examples/jsm/controls/OrbitControls";
import { TransformControls } from "../../../../node_modules/three/examples/jsm/controls/TransformControls";
import { EffectComposer } from "../../../../node_modules/three/examples/jsm/postprocessing/EffectComposer.js";
import { RenderPass } from "../../../../node_modules/three/examples/jsm/postprocessing/RenderPass.js";
import { UnrealBloomPass } from "../../../../node_modules/three/examples/jsm/postprocessing/UnrealBloomPass.js";
import { GUI } from "../../../../node_modules/three/examples/jsm/libs/dat.gui.module";

let renderer = new THREE.WebGLRenderer({ antialias: true });
let camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  1,
  10000
);
let scene = new THREE.Scene();
let gui = null;
// 其他属性
let renderScene = new RenderPass(scene, camera);
let stats = new Stats();
let raycaster = new THREE.Raycaster();
let mouse = new THREE.Vector2();
let bloomPass = new UnrealBloomPass(
  new THREE.Vector2(window.innerWidth, window.innerHeight),
  1.5,
  0.4,
  0.85
);
let composer = null;
let showUpdateTranformControls = false;

// 使用嵌套对象时，你可以选择使用 `reactive` 代替 `ref`
let lightBox = { ambientLight: new THREE.AmbientLight("rgb(255, 255, 255)", 1) };
let helperBox = {
  axesHelper: new THREE.AxesHelper(10000),
  gridHelper: new THREE.GridHelper(1500, 30, "white", "rgb(150, 150, 150)"),
};

let guiParam = {};

// 初始化 objectSetting
let objectSetting = {
  planeTotal: 100,
  sphereTotal: 1000,
  r1: 120,
  r2: 200,
  maxY: 2000,
  minY: -2000,
  planSetting: {
    minWidth: 30,
    minHeight: 700,
    maxWidth: 50,
    maxHeight: 1000,
  },
  sphereSetting: {
    scaleMax: 30,
    scaleMin: 15,
  },
};

let cameraDirection = 1;
let clock = new THREE.Clock();
let orbitControls = new OrbitControls(camera, renderer.domElement);
let transformControls = new TransformControls(camera, renderer.domElement);

let animationControl = true
let animationSpeed = 5 
let animationFrame = ""




onMounted(() => inited());

let inited = () => {
  initRender();
  initCamera();
  initBloomPass();
  initComposer();
  initLight();
  // initStats();
  initOrbitControls();
  initObject();
  // initGui();
  updateRenderer();
};

let threeCanvas = ref(null);

// 初始渲染器
let initRender = () => {
  renderer.setSize(window.innerWidth, window.innerHeight);
  // renderer.shadowMap.enabled = true // 渲染器阴影渲染
  // renderer.shadowMap.type = THREE.PCFSoftShadowMap // 阴影类型
  renderer.toneMapping = THREE.ReinhardToneMapping;
  renderer.toneMappingExposure = Math.pow(1.2, 4.0);
  threeCanvas.value.appendChild(renderer.domElement);
  renderer.setClearColor("rgb(0, 0, 0)");
};

let initComposer = () => {
  composer = new EffectComposer(renderer);

  composer.addPass(renderScene);
  composer.addPass(bloomPass);
};

let initBloomPass = () => {
  bloomPass.threshold = 0;
  bloomPass.strength = 1.2;
  bloomPass.radius = 0.3;
};

let initLight = () => {
  scene.add(lightBox.ambientLight);
};

let initCamera = () => {
  camera.position.x = 0;
  camera.position.y = 2000;
  camera.position.z = 0;
  camera.up.x = 0;
  camera.up.y = 1;
  camera.up.z = 0;
  camera.lookAt(new THREE.Vector3(0, 0, 0));
};

let initStats = () => {
  stats = new Stats(); // 资源监视器
  stats.setMode(0);
  stats.domElement.id = "three-stats";
  stats.domElement.style.position = "absolute";
  stats.domElement.style.left = "unset";
  stats.domElement.style.right = "300px";
  stats.domElement.style.top = "0px";
  document.body.appendChild(stats.domElement);
};

let initGui = () => {
  gui = new GUI(); // 控制台
  guiParam = {
    // 控制参数
    animation: animationControl,
    animationSpeed: animationSpeed,
    exposure: Math.pow(renderer.toneMappingExposure, 1 / 4),
    threshold: bloomPass.threshold,
    strength: bloomPass.strength,
    radius: bloomPass.radius,
  };
  gui.add(guiParam, "animation").onChange((data) => {
    animationControl = data;
  });
  gui.add(guiParam, "animationSpeed", 1, 20, 1).onChange((data) => {
    animationSpeed = data;
  });
  gui.add(guiParam, "exposure", 0, 2, 0.1).onChange((data) => {
    renderer.toneMappingExposure = Math.pow(data, 4.0);
  });
  gui.add(guiParam, "threshold", 0, 1, 0.1).onChange((data) => {
    bloomPass.threshold = data;
  });
  gui.add(guiParam, "strength", 0, 4, 0.1).onChange((data) => {
    bloomPass.strength = data;
  });
  gui.add(guiParam, "radius", 0, 1, 0.1).onChange((data) => {
    bloomPass.radius = data;
  });
};

let initOrbitControls = () => {
  orbitControls.autoRotate = true;
  orbitControls.enablePan = true;
  orbitControls.mouseButtons = {
    LEFT: "",
    MIDDLE: THREE.MOUSE.DOLLY,
    RIGHT: THREE.MOUSE.ROTATE,
  };
  orbitControls.keys = {
    LEFT: 65, // a
    UP: 87, // w
    RIGHT: 68, // d
    BOTTOM: 83, // s
  };
  orbitControls.target = new THREE.Vector3(0, -3000, 0);
};

let initObject = () => {
  // 生成随机颜色
  let getColor = () => {
    let r = Math.round(Math.random() * 255);
    let g = Math.round(Math.random() * 255);
    let b = Math.round(Math.random() * 255);
    return `rgb(${r}, ${g}, ${b})`;
  };
  // 生成平面随机位置
  let getPlanePositon = () => {
    let max = objectSetting.r2;
    let min = objectSetting.r1;
    let maxY = objectSetting.maxY;
    let minY = objectSetting.minY;
    let x =
      (Math.floor(Math.random() * (max - min + 1)) + min) *
      (Math.random() + 0.2) *
      (Math.random() > 0.5 ? 1 : -1);
    let y = Math.floor(Math.random() * (maxY - minY + 1)) + minY;
    let z =
      (Math.floor(Math.random() * (max - min + 1)) + min) *
      (Math.random() + 0.2) *
      (Math.random() > 0.5 ? 1 : -1);
    return {
      x,
      y,
      z,
    };
  };
  // 生成球体随机位置
  let getSpherePositon = () => {
    let max = objectSetting.r2;
    let min = objectSetting.r1;
    let maxY = objectSetting.maxY;
    let minY = objectSetting.minY;
    let x =
      (Math.floor(Math.random() * (max - min + 1)) + min) *
      Math.random() *
      (Math.random() > 0.5 ? 1 : -1);
    let y = Math.floor(Math.random() * (maxY - minY + 1)) + minY;
    let z =
      (Math.floor(Math.random() * (max - min + 1)) + min) *
      Math.random() *
      (Math.random() > 0.5 ? 1 : -1);
    return {
      x,
      y,
      z,
    };
  };
  // 先生成面
  for (let planNum = 0; planNum < objectSetting.planeTotal; planNum += 1) {
    let material = new THREE.MeshStandardMaterial({
      color: getColor(),
      roughness: 0,
      metalness: 0,
    });
    material.wireframe = Math.random() > 0.1;
    material.transparent = true;
    material.opacity = Math.random() * 0.8;
    let widthDept = Math.round(Math.random() * 6);
    let geometry = new THREE.PlaneBufferGeometry(
      Math.floor(
        Math.random() *
          (objectSetting.planSetting.maxWidth - objectSetting.planSetting.minWidth + 1)
      ) + objectSetting.planSetting.minWidth,
      Math.floor(
        Math.random() *
          (objectSetting.planSetting.maxHeight - objectSetting.planSetting.minHeight + 1)
      ) + objectSetting.planSetting.minHeight,
      widthDept < 2 ? 0 : widthDept,
      1
    );
    let plane = new THREE.Mesh(geometry, material);
    let position = getPlanePositon();
    plane.position.set(position.x, position.y, position.z);
    plane.lookAt(0, position.y, 0);
    scene.add(plane);
  }
  // 生成球体
  for (let planNum = 0; planNum < objectSetting.sphereTotal; planNum += 1) {
    let material = new THREE.MeshStandardMaterial({
      color: getColor(),
      roughness: 0,
      metalness: 0,
    });
    let geometry = new THREE.SphereBufferGeometry(1, 10, 16, 6);
    let sphere = new THREE.Mesh(geometry, material);
    let position = getSpherePositon();
    sphere.position.set(position.x, position.y, position.z);
    let max = objectSetting.sphereSetting.scaleMax;
    let min = objectSetting.sphereSetting.scaleMin;
    sphere.scale.set(1, Math.floor(Math.random() * (max - min + 1)) + min, 1);
    scene.add(sphere);
  }
};

let animation = () => {
  if (camera.position.y > 2000) {
    cameraDirection = 1;
    orbitControls.target = new THREE.Vector3(0, -2000, 0);
  } else if (camera.position.y < -2000) {
    cameraDirection = -1;
    orbitControls.target = new THREE.Vector3(0, 2000, 0);
  }
  camera.position.y -= animationSpeed * cameraDirection;
};

let updateRenderer = () => {
  let delta = clock.getDelta();
  orbitControls.update(delta);
  if (animationControl) {
    animation();
  }
  composer.render();
  stats.update();
  animationFrame = requestAnimationFrame(updateRenderer);
};
</script>

<style scoped>
/* same styles*/
</style>
